<?php
/** 
*@Description: 底层控制器
* 
* @author      tangchuan
*/
class AbstractController {

	protected static $childs = array();
	protected  $_className ="";
	protected  $_bean=null;


    

    /**
     * 根据url中的ctrlName ,func重定向到对应的控制器中的方法，并自动名称自动讲$REQUEST中的参数注入到控制器方法的参数中(包括上传的文件也会被注入到对应的方法参数)
     * 例如：http://localhost:81/backend/sign!getInterdayRecords/user_id=90&sign_date=2016-06-25
     * 以上url中会调用SignController控制器中的getInterdayRecords方法,user_id,和sign_date会被自动注入到getInterdayRecords方法的user_id参数和sign_date参数
     * public function addSignRecord($post_json,$transaction = null){
     *      
     * }
     * 方法的参数中如果包含以下几个特定名称参数：$transaction,$post_json,$filter等会有特定的操作，如以上addSignRecord方法：
     * 1、$post_json:被注入的是客户端以Raw方法传输的数据
     * 2、$filter:被注入的是调用端序列化后的filter对象
     * 3、$transaction如果方法中带有了改参数，则该方法被调用前(即:执行beforeInvoke方法的时候)会自动开启数据库事务，
     *    如果方法顺利调用结束(即:执行afterInvoke方法的时候)事务会被自动提交，如果出现异常，事务会被自动回滚
     * @return 如果被调用的方法有返回值则以json形式输出返回结果到调用端
     *         如果没返回值则输出默认格式的信息到调用端
     *         如果调用过程中补捕获到异常，则异常信息会返回给调用端
     */
    public static function dispatch() {
        $actionRoot = Utils::GetRequestParam(CONTROLLER_PATH_KEY);
        $actionName = Utils::GetRequestParam(CONTROLLER_NAME_KEY);
        $methodName = Utils::GetRequestParam(CONTROLLER_FUNC_KEY);
       
        $class = AbstractController::LoadControllerClass($actionName,$actionRoot);
        $instance  = $class->newInstance();

        $method = $class->getMethod($methodName);
        $postParams = $method->getParameters(); 
        $invokeParams = array();
       

        if($postParams!=null){
            for($i=0;$i<count($postParams);$i++){
                $name = $postParams[$i]->name;
                //如果方法中含有名为filter的参数则自动从_REQUEST中获取参数并填充SqlFilter对象

                if($name == POST_FILTER_PARAM_KEY){
                	$filter = new SqlFilter();
                    if(!empty($_REQUEST[$name])){
                        try{
                            $jsonArray = json_decode($_REQUEST[$name], true);
                            for($j=0;$j<count($jsonArray);$j++){
                                $json = $jsonArray[$j];
                                $filter->addFilter($json["field"],$json["op"],$json["value"]);
                            }
                        
                        }catch(Exception $ex){}
                    
                    }
                    array_push($invokeParams,$filter);
                }
                else if($name == POST_JSON_PARAM_KEY){

                    //if(!empty($_REQUEST[$name])){
                        try{
                            $jsonData = null;
                            $str_date =file_get_contents('php://input');
                            parse_str($str_date,$jsonData);
                            //$jsonData = json_encode($jsonData,true);
                            
                          
                            array_push($invokeParams,$jsonData);
                        }catch(Exception $ex){}
                    //}

                }
                else if (UploadUtil::is_files_upload($name)){

                     $upload = new UploadUtil($name,ROOT_PATH.DIRECTORY_SEPARATOR.UPLOAD_FILE_ROOT_DIR.DIRECTORY_SEPARATOR);
                     $uploadFiles = $upload ->uploadFiles();
                     array_push($invokeParams,$uploadFiles);
                }
                else if(!empty($_REQUEST[$name])){
                    array_push($invokeParams,Utils::GetRequestParam($name));
                }

            }
        }



        $beforeInvoke = $class->getMethod("beforeInvoke");
        if($beforeInvoke!=null){
            $beforeInvoke->invokeArgs($instance,array($actionName,$method,$invokeParams));
        }

        $msg = $method->invokeArgs($instance, $invokeParams);
        
        $afterInvoke = $class->getMethod("afterInvoke");
        if($afterInvoke!=null){
            $afterInvoke->invokeArgs($instance,array($actionName,$method,$invokeParams));
        }

        if($msg!=null ){
            echo json_encode($msg);
        }
        else{
            $msg = new Message();
            $msg->toJson();
        }

    }


    /**
     * 控制器方法被调用前执行的操作（该方法被框架自动调用，可根据需要在派生类中重载，重载后需要调用parent::beforeInvoke）
     * 基中主要用来判断是否需要自动开启事务
     * @param $actionName    控制器名称
     * @param $method        被调用的方法名称
     * @param $invokeParams  被执行的实参数组
     */
    public function  beforeInvoke($actionName,$method,$invokeParams){
        if($this->_className!= null &&  $this->_className!=""){
            $this->_bean = AbstractBean::LoadBean($this->_className);
        }
            
        $params = $method->getParameters();
        if($params!=null){
            for($i=0;$i<count($params);$i++){
                $name = $params[$i]->name;
                //如果方法中含有名为transaction的参数则开启事务
                if($name == "transaction"){
                    AbstractDbUtils::pdo_connection(CONNECTION_KEY,true);
                }
            }
        }

    }

    /**
     * 控制器方法被调用后执行的操作（该方法被框架自动调用，可根据需要在派生类中重载，重载后需要调用parent::afterInvoke）
     * 基中主要用来判断是否需要自动提交事务
     * @param $actionName    控制器名称
     * @param $method        被调用的方法名称
     * @param $invokeParams  被执行的实参数组
     */
    public function  afterInvoke($actionName,$method,$invokeParams){
        $conn = AbstractDbUtils::GetOpenedConnection();
        if($conn !=null && $conn->transaction_opened == true){
            $conn->commit();
        }
    }


    public static function LoadController($className,$controllerPath) {

        if (self::$childs['Controllers'][$className] instanceof $className) {
            $class = get_class(self::$childs['Controllers'][$className]);
            $Controller = new $class();
            $Controller->_className = $className;
        } else {
            try {
                $class = AbstractController::GetControllerPath($className,$controllerPath);
                @self::$childs['Controllers'][$className] = $class;
                $Controller = @self::$childs['Controllers'][$className];
                $Controller->_className = $className;
            }
            catch(Exception $e) {
                die();
            }
        }
       
        return $Controller;
	}

	public static function LoadControllerClass($controllerName,$controllerRoot){
        $firsChar =substr($controllerName,0,1);
        $controllerName = strtoupper($firsChar).substr($controllerName,1);
        if(strstr($controllerName,"Controller")==false){
			$controllerName = $controllerName."Controller";
		}
		$controllerRoot = str_replace("/", DIRECTORY_SEPARATOR, $controllerRoot);
        $file=APP_PATH.DIRECTORY_SEPARATOR.$controllerRoot.DIRECTORY_SEPARATOR.$controllerName.".php";
        if (is_readable($file)) {
       		require_once $file; 
	    }
        return new ReflectionClass($controllerName);
        
    }

	public static function GetControllerPath($controllerName,$controllerRoot){
       
        $firsChar =substr($controllerName,0,1);
        $controllerName = strtoupper($firsChar).substr($controllerName,1);

		if(strstr($controllerName,"Controller")==false){
			$controllerName = $controllerName."Controller";
		}
		$controllerRoot = str_replace("/", DIRECTORY_SEPARATOR, $controllerRoot);
        $file=APP_PATH.DIRECTORY_SEPARATOR.$controllerRoot.DIRECTORY_SEPARATOR.$controllerName.".php";
        if (is_readable($file)) {
       		require_once $file; 
			return new $controllerName();
        } 
        
  }


}
?>